package com.pig4cloud.pigx.common.customize.api.util;

import com.alibaba.fastjson.JSONObject;
import com.pig4cloud.pigx.common.core.constant.SecurityConstants;
import com.pig4cloud.pigx.common.customize.api.enums.AbnormalEnum;
import com.pig4cloud.pigx.common.customize.api.exception.OpenApiException;
import com.pig4cloud.pigx.common.customize.i18n.util.MessageUtils;
import com.pig4cloud.pigx.common.customize.redis.constants.RedisKeyEnum;
import lombok.RequiredArgsConstructor;
import org.apache.logging.log4j.util.Strings;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;

import javax.servlet.http.HttpServletRequest;
import java.util.Objects;

/**
 * 开放api工具类
 *
 * @since 2022/11/9 11:42
 */
@Component
@RequiredArgsConstructor
public class OpenApiUtil {

	/**
	 * 根据异常枚举抛出异常
	 *
	 * @param enums 枚举
	 * @since 2022/11/9 11:43
	 */
	public static void throwError(AbnormalEnum.MSG enums) {
		throw new OpenApiException(enums.getCode(), MessageUtils.get(enums.getMessage()));
	}

	/**
	 * 根据异常枚举抛出异常
	 *
	 * @param enums 枚举
	 * @since 2022/11/9 11:43
	 */
	public static void throwError(AbnormalEnum.MSG enums, Object... args) {
		throw new OpenApiException(enums.getCode(), MessageUtils.get(enums.getMessage(), args));
	}

	/**
	 * 根据异常枚举获取异常
	 *
	 * @param enums 枚举
	 * @param args  异常补充信息
	 * @since 2022/11/10 16:43
	 */
	public static OpenApiException getError(AbnormalEnum.MSG enums, Object... args) {
		return new OpenApiException(enums.getCode(), MessageUtils.get(enums.getMessage(), args));
	}

	/**
	 * 根据异常枚举获取异常
	 *
	 * @param enums 枚举
	 * @since 2022/11/10 16:43
	 */
	public static OpenApiException getError(AbnormalEnum.MSG enums) {
		return new OpenApiException(enums.getCode(), MessageUtils.get(enums.getMessage()));
	}

	/**
	 * 从url参数/请求体参数中获取指定参数
	 *
	 * @param name        参数名
	 * @param queryParams url参数
	 * @param bodyParams  请求体参数
	 * @param remove      获取后是否移除
	 * @param notNull     是否不能为空
	 * @return {@link String}
	 * @since 2022/11/9 16:16
	 */
	public static String getStringValue(String name, MultiValueMap<String, String> queryParams, JSONObject bodyParams, boolean remove, boolean notNull) {
		// 从url参数中寻找参数
		if (!Objects.isNull(queryParams) && queryParams.containsKey(name)) {
			String signature = queryParams.getFirst(name);
			// 如果为空
			if (notNull && Strings.isBlank(signature)) {
				throw new OpenApiException(11002, "A mandatory parameter was not sent, was empty/null, or malformed.");
			}

			if (remove) {
				// 从url参数中移除参数
				queryParams.remove(name);
			}

			return signature;
		}

		// 如果为空
		if (Objects.isNull(bodyParams)) {
			if (notNull) {
				throw new OpenApiException(11002, "A mandatory parameter was not sent, was empty/null, or malformed.");
			}

			return null;
		}

		String signature = bodyParams.getString(name);
		// 如果为空
		if (notNull && Strings.isBlank(signature)) {
			throw new OpenApiException(11002, "A mandatory parameter was not sent, was empty/null, or malformed.");
		}

		if (remove) {
			// 从请求体中寻找参数
			bodyParams.remove(name);
		}

		return signature;
	}

	/**
	 * 从url参数/请求体参数中获取指定参数
	 *
	 * @param name        参数名
	 * @param queryParams url参数
	 * @param bodyParams  请求体参数
	 * @return {@link String}
	 * @since 2022/11/9 16:16
	 */
	public static String getStringValue(String name, MultiValueMap<String, String> queryParams, JSONObject bodyParams) {
		return getStringValue(name, queryParams, bodyParams, false, true);
	}

	/**
	 * 从url参数中获取指定参数
	 *
	 * @param name        参数名
	 * @param queryParams url参数
	 * @return {@link String}
	 * @since 2022/11/9 16:16
	 */
	public static String getStringValue(String name, MultiValueMap<String, String> queryParams) {
		return getStringValue(name, queryParams, null, false, true);
	}

	/**
	 * 从url参数/请求体参数中获取指定参数
	 *
	 * @param name       参数名
	 * @param bodyParams 请求体参数
	 * @return {@link String}
	 * @since 2022/11/9 16:16
	 */
	public static String getStringValue(String name, JSONObject bodyParams) {
		return getStringValue(name, null, bodyParams, false, true);
	}

	/**
	 * 从请求头中获取参数
	 *
	 * @param request 请求包
	 * @param name    参数名称
	 * @return {@link String}
	 * @since 2022/11/11 15:39
	 */
	public static String getStringValueFromHeader(HttpServletRequest request, String name) {
		return getStringValueFromHeader(request, name, true);
	}

	/**
	 * 从请求头中获取参数
	 *
	 * @param request 请求包
	 * @param name    参数名称
	 * @param notNull 不允许为空
	 * @return {@link String}
	 * @since 2022/11/11 15:39
	 */
	public static String getStringValueFromHeader(HttpServletRequest request, String name, boolean notNull) {
		String value = request.getHeader(name);
		if (Strings.isBlank(value)) {
			if (notNull) {
				throw new OpenApiException(11002, "A mandatory parameter was not sent, was empty/null, or malformed.");
			}

			return null;
		}

		return value;
	}

	/**
	 * 获取登录Token的RedisKey
	 *
	 * @param accessKey 访问密钥
	 * @param clientIp  客户端IP
	 * @return {@link String}
	 * @since 2022/11/10 15:46
	 */
	public static String getTokenRedisKey(String accessKey, String clientIp) {
		RedisKeyEnum loginToken = RedisKeyEnum.ApiLoginToken;
		return String.format(loginToken.getKey(), accessKey + "_" + clientIp);
	}

	/**
	 * 获取nonce在Redis的key
	 *
	 * @param nonce nonce
	 * @return {@link String}
	 * @since 2022/11/9 16:45
	 */
	public static String getNonceRedisKey(String nonce) {
		RedisKeyEnum apiNonce = RedisKeyEnum.ApiNonce;
		return String.format(apiNonce.getKey(), nonce);
	}

	/**
	 * 获取nonce在Redis的key
	 *
	 * @param clientIp 客户端IP
	 * @return {@link String}
	 * @since 2022/11/9 16:45
	 */
	public static String getReplayAttackRedisKey(String clientIp) {
		RedisKeyEnum replayAttack = RedisKeyEnum.ApiReplayAttack;
		return String.format(replayAttack.getKey(), clientIp);
	}

	/**
	 * 获取rateLimit在Redis的key
	 *
	 * @param accessKey   访问密钥
	 * @param clientIp    客户端IP
	 * @param requestPath 请求路径
	 * @return {@link String}
	 * @since 2022/11/9 16:45
	 */
	public static String getRateLimitRedisKey(String accessKey, String clientIp, String requestPath) {
		RedisKeyEnum rateLimit = RedisKeyEnum.ApiRateLimit;
		return String.format(rateLimit.getKey(), accessKey + "_" + clientIp + "_" + requestPath);
	}

	/**
	 * 获取wsRateLimit在Redis的key
	 *
	 * @param accessKey 访问密钥
	 * @param clientIp  客户端IP
	 * @return {@link String}
	 * @since 2022/11/9 16:45
	 */
	public static String getWsRateLimitRedisKey(String accessKey, String clientIp) {
		RedisKeyEnum wsRateLimit = RedisKeyEnum.ApiWsRateLimit;
		return String.format(wsRateLimit.getKey(), accessKey + "_" + clientIp);
	}

	/**
	 * 从nginx客户端IP追踪中获取真实客户端IP地址
	 *
	 * @param clientIp nginx IP追踪
	 * @return {@link String}
	 * @since 2022/11/14 16:15
	 */
	public static String getClientIp(String clientIp) {
		if (Strings.isBlank(clientIp)) {
			// 无效的IP
			throw new OpenApiException(20004, "Invalid API-key, IP, or permissions for action.");
		}

		String[] split = clientIp.split(SecurityConstants.X_CLIENT_IP_SPLIT);
		return split[0];
	}
}
